﻿using System;
using System.ComponentModel.Design;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Task = System.Threading.Tasks.Task;

namespace AutoNotes
{
    /// <summary>
    /// Command handler
    /// </summary>
    internal sealed class NoteCommand
    {
        /// <summary>
        /// 配置注释按钮
        /// </summary>
        public const int ConfigNotesCommandId = 0x0102;
        /// <summary>
        /// Summary注释命令按钮
        /// </summary>
        public const int SummaryNotesCommandId = 0x0202;
        /// <summary>
        /// 普通注释
        /// </summary>
        public const int OriginalNotesCommandId = 0x0203;

        /// <summary>
        /// Command menu group (command set GUID).
        /// </summary>
        public static readonly Guid CommandSet = new Guid("825a2cd2-a349-4349-9b72-340649e8373b");

        /// <summary>
        /// VS Package that provides this command, not null.
        /// </summary>
        private readonly AsyncPackage package;

        /// <summary>
        /// Initializes a new instance of the <see cref="NoteCommand"/> class.
        /// Adds our command handlers for menu (commands must exist in the command table file)
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        /// <param name="commandService">Command service to add command to, not null.</param>
        private NoteCommand(AsyncPackage package, OleMenuCommandService commandService)
        {
            this.package = package ?? throw new ArgumentNullException(nameof(package));
            commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));

            //配置注释
            var configNotesCommandId = new CommandID(CommandSet, ConfigNotesCommandId);
            var configNotesMenuItem = new MenuCommand(this.ConfigNotesCommandExecute, configNotesCommandId);
            commandService.AddCommand(configNotesMenuItem);

            //Summary注释
            var summaryNotesCommandId = new CommandID(CommandSet, SummaryNotesCommandId);
            var summaryNotesMenuItem = new MenuCommand(this.SummaryNotesCommandExecute, summaryNotesCommandId);
            commandService.AddCommand(summaryNotesMenuItem);

            //普通注释
            var originalNotesCommandId = new CommandID(CommandSet, OriginalNotesCommandId);
            var originalNotesMenuItem = new MenuCommand(this.OriginalNotesCommandExecute, originalNotesCommandId);
            commandService.AddCommand(originalNotesMenuItem);
        }

        /// <summary>
        /// Gets the instance of the command.
        /// </summary>
        public static NoteCommand Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the service provider from the owner package.
        /// </summary>
        private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        /// <summary>
        /// Initializes the singleton instance of the command.
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        public static async Task InitializeAsync(AsyncPackage package)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            OleMenuCommandService commandService = await package.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService;
            Instance = new NoteCommand(package, commandService);
        }

        /// <summary>
        /// 配置注释
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void ConfigNotesCommandExecute(object sender, EventArgs e)
        {
            ConfigNotesForm form = new ConfigNotesForm();
            form.ShowDialog();
        }

        /// <summary>
        /// Summary注释
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void SummaryNotesCommandExecute(object sender, EventArgs e)
        {
            var dte = this.ServiceProvider.GetServiceAsync(typeof(DTE)).Result as DTE;
            if (dte == null) return;
            if (dte.ActiveDocument == null) return;
            var selection = dte.ActiveDocument.Selection as TextSelection;
            if (selection == null) return;

            //删除所选内容
            if (!selection.IsEmpty)
                selection.Delete();

            string str = ConfigSettings.Default[Constants.SummaryNotes].ToString();
            Note(selection, str);
        }

        /// <summary>
        /// 普通注释
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void OriginalNotesCommandExecute(object sender, EventArgs e)
        {
            var dte = this.ServiceProvider.GetServiceAsync(typeof(DTE)).Result as DTE;
            if (dte == null) return;
            if (dte.ActiveDocument == null) return;
            var selection = dte.ActiveDocument.Selection as TextSelection;
            if (selection == null) return;

            string str = ConfigSettings.Default[Constants.OriginalNotes].ToString();
            Note(selection, str);
        }

        private void Note(TextSelection selection, string str)
        {
            if (selection == null) return;

            //删除所选内容
            if (!selection.IsEmpty)
                selection.Delete();

            var notes = str.Replace("@company", (ConfigSettings.Default[Constants.company] ?? "").ToString());
            notes = notes.Replace("@year", (DateTime.Now.Year).ToString());
            notes = notes.Replace("@yourname", (ConfigSettings.Default[Constants.Name] ?? "").ToString());
            var dateFomate = (ConfigSettings.Default[Constants.TimeFormate] ?? "yyyy-MM-dd HH:mm:ss").ToString();
            notes = notes.Replace("@time", DateTime.Now.ToString(dateFomate));

            //移动到该行的首行
            selection.StartOfLine();
            //插入换行符
            selection.NewLine();
            //向上移动一行
            selection.LineUp();
            //插入
            selection.Insert(notes);
            //格式化代码
            selection.SmartFormat();
        }
    }
}
